package cn.edu.gdut.deepcode.service.impl;

import cn.edu.gdut.deepcode.annotation.CanvasIdCheckPoint;
import cn.edu.gdut.deepcode.annotation.GenSharedCodeCheckPoint;
import cn.edu.gdut.deepcode.component.CacheComponent;
import cn.edu.gdut.deepcode.context.UserContext;
import cn.edu.gdut.deepcode.domain.po.Canvas;
import cn.edu.gdut.deepcode.domain.po.CanvasShare;
import cn.edu.gdut.deepcode.domain.po.Result;
import cn.edu.gdut.deepcode.mapper.CanvasSharedMapper;
import cn.edu.gdut.deepcode.service.ICanvasService;
import cn.edu.gdut.deepcode.service.ICanvasSharedService;
import cn.edu.gdut.deepcode.utils.CommonUtils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static cn.edu.gdut.deepcode.constant.AbnormalInfoConstant.CS_EI_1;
import static cn.edu.gdut.deepcode.constant.AbnormalInfoConstant.CS_EI_2;
import static cn.edu.gdut.deepcode.constant.CacheConstant.*;
import static cn.edu.gdut.deepcode.constant.ReqRespConstant.*;

/**
 * <p>
 * 画布分享表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-11
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CanvasSharedServiceImpl extends ServiceImpl<CanvasSharedMapper, CanvasShare> implements ICanvasSharedService {

//    private final MD5Utils md5Utils;

    private final StringRedisTemplate redisTemplate;

    private final ICanvasService canvasService;

    private final CacheComponent cacheComponent;


    @Override
    @CanvasIdCheckPoint
    @GenSharedCodeCheckPoint
    public Result<String> genSharedCode(Long canvasId, Long expire) {
        // 生成分享码
        Long userId = UserContext.getUser();
        String sharedCode = CommonUtils.encode(userId, canvasId);
        // 修改画布分享状态
        Db.lambdaUpdate(Canvas.class)
                .eq(Canvas::getUserId,userId)
                .eq(Canvas::getCanvasId, canvasId)
                .set(Canvas::getSharing, true)
                .update();
        // 放入缓存
        if (PERMANENT.equals(expire)) {
            // 不过期的
            redisTemplate.opsForValue().set(CANVAS_SHARED_CODE_PREFIX +canvasId, sharedCode);
        }else {
            redisTemplate.opsForValue().set(CANVAS_SHARED_CODE_PREFIX +canvasId, sharedCode, expire, TimeUnit.MINUTES);
        }
        // 清空当前用户的相关缓存
        redisTemplate.delete(CANVAS_INFO_LIST_CACHE_KEY_PREFIX+userId);
        redisTemplate.delete(CANVAS_INFO_VALUE_CACHE_KEY_PREFIX+userId+canvasId);

        // 返回分享码
        return Result.success(COMMON_SUCCESSFUL_MSG, sharedCode);
    }



    @Override
    public Result<Long> checkSharedCodeAndGetCanvas(String sharedCode) {
        // 对分享码进行解码
        String decode = CommonUtils.decode(sharedCode);
        // 获取画布id,画布主人id
        String[] split = decode.split(SHARED_CODE_SEPARATOR);
        Long ownerId = Long.valueOf(split[0]);
        Long canvasId = Long.valueOf(split[1]);
        // 根据画布id获取服务端的分享码
        String code = cacheComponent.getRedisTemplate().opsForValue().get(CANVAS_SHARED_CODE_PREFIX +canvasId);
        if (StrUtil.isBlank(code)) {
            // 分享码已过期
            return Result.error(
                    SHARED_CODE_EXPIRED_CODE,
                    SHARED_CODE_EXPIRED_MSG);
        }
        if (!sharedCode.equals(code)) {
            // 客户端分享码与服务端分享码不一致
            return Result.error(
                    ILLEGAL_SHARED_CODE_CODE,
                    ILLEGAL_SHARED_CODE_MSG);
        }
        Long userId = UserContext.getUser();
        if (userId.equals(ownerId)) {
            // 校验分享码的用户为分享码主人
            return Result.success(
                    UNNECESSARY_SHARED_CODE_CHECK_CODE,
                    UNNECESSARY_SHARED_CODE_CHECK_MSG);
        }
        if (Db.lambdaQuery(Canvas.class)
                .eq(Canvas::getUserId, userId)
                .eq(Canvas::getCanvasId, canvasId)
                .count() != 0
        ) {
            // 当前用户已校验过分享码
            return Result.success(
                    SHARED_CODE_REPEATED_CHECK_CODE,
                    SHARED_CODE_REPEATED_CHECK_MSG
            );
        }

        // 根据画布id,画布主人id查询画布信息
        Canvas canvasOld = Db.lambdaQuery(Canvas.class)
                .eq(Canvas::getUserId, ownerId)
                .eq(Canvas::getCanvasId, canvasId)
                .one();
        if (BeanUtil.isEmpty(canvasOld)) {
            // 分享码对应的画布信息异常
            log.warn(CS_EI_1, List.of(
                    userId,
                            sharedCode,
                            decode,
                            code,
                            canvasOld
                    )
            );
            return Result.success();
        }
        // 为当前用户新增画布
        Canvas canvasNew = new Canvas();
        canvasNew
                .setCanvasId(canvasId)
                .setUserId(userId)
                .setIsOwner(false)
                .setOwnerId(canvasOld.getOwnerId())
                .setImg(canvasOld.getImg())
                .setTitle(canvasOld.getTitle())
                .setCreateTime(LocalDateTime.now());
        canvasService.save(canvasNew);
        // 清空当前用户的相关缓存
        redisTemplate.delete(CANVAS_INFO_LIST_CACHE_KEY_PREFIX+userId);
        redisTemplate.delete(CANVAS_INFO_VALUE_CACHE_KEY_PREFIX+userId+canvasId);
        return Result.success(canvasId);
    }


    @Override
    public Result<?> cancelSharing(Long canvasId) {
        // 根据canvasId、userId获取完整画布基础信息
        Long userId = UserContext.getUser();
        Canvas canvas = Db.lambdaQuery(Canvas.class)
                .eq(Canvas::getUserId, userId)
                .eq(Canvas::getCanvasId, canvasId)
                .one();
        if (
                BeanUtil.isEmpty(canvas) ||
                        !userId.equals(canvas.getOwnerId())
        ) {
            // 画布信息异常或当前用户并不是画布的主人
            CommonUtils.recordErrorInfoAndThrowException(
                    CS_EI_2,
                    List.of(userId, canvasId, canvas)
            );
        }
        // 设置画布分享状态为false
        Db.lambdaUpdate(Canvas.class)
                .eq(Canvas::getUserId,userId)
                .eq(Canvas::getCanvasId, canvasId)
                .set(Canvas::getSharing, false)
                .update();
        // 如果有必要则移除分享码
        destroySharedCode(canvasId);
        // 获取协助者的userId
        List<Long> ids = Db.lambdaQuery(Canvas.class)
                .ne(Canvas::getUserId, userId)
                .eq(Canvas::getCanvasId, canvasId)
                .list().stream().map(Canvas::getUserId).toList();
        // 删除协作者的画布信息
        canvasService.deleteCollaboratorCanvasInfos(Collections.singletonMap(userId,ids),canvasId);

        return Result.success();
    }

    public void destroySharedCode(Long canvasId) {
        // 获取分享码的key,查看分享码是否过期
        String key = CANVAS_SHARED_CODE_PREFIX +canvasId;
        if (!EXPIRED.equals(cacheComponent.sharedCodeExpired(key))) {
            // 未过期手动删除
            redisTemplate.delete(key);
        }
    }

    @Override
    public Result<String> getSharedCodeByCanvasId(Long canvasId) {
        // 根据canvasId获取分享码
        String sharedCode = cacheComponent.getValueCache(CANVAS_SHARED_CODE_PREFIX +canvasId);
        if (StrUtil.isBlank(sharedCode)) {
            // 分享码过期了
            return Result.success();
        }
        // 返回分享码
        return Result.success(COMMON_SUCCESSFUL_MSG, sharedCode);
    }


}
